#!/bin/sh
#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
set +x
#@function: backup oracle db and log

SCRIPT_ROOT_PATH=$1
PID=$2
PARAM_NUM=$3
SCRIPTPID=$$

. "${SCRIPT_ROOT_PATH}/oracle_sbin_func.sh"
. "${SCRIPT_ROOT_PATH}/oracle_native_backup_func.sh"
. "${SCRIPT_ROOT_PATH}/oracle_native_archive_backup_func.sh"

echo ${SCRIPTPID} > "${SCRIPTPID_FILE}"


#********************************get param from pip ********************************
PARAM_CONTENT=`read_input_param "${PARAM_NUM}"`
test -z "$PARAM_CONTENT"              && exit_with_error "PARAM_FILE"

DBNAME=`get_value "${PARAM_CONTENT}" AppName`
DBUUID=`get_value "${PARAM_CONTENT}" DBUUID`
DBINSTANCE=`get_value "${PARAM_CONTENT}" InstanceName`
DBUSER=`get_value "${PARAM_CONTENT}" UserName`
DBUSERPWD=`get_value "${PARAM_CONTENT}" Password`
ASMUSER=`get_value "${PARAM_CONTENT}" ASMUserName`
ASMUSERPWD=`get_value "${PARAM_CONTENT}" ASMPassword`
CHANNELS=`get_value "${PARAM_CONTENT}" Channel`
BACKUP_PATH_LIST=`get_value "${PARAM_CONTENT}" DataPath`
# level 0 is full backup, 1 is differential increment , 2 is cumulative increment
LEVEL=`get_value "${PARAM_CONTENT}" Level`
QOS=`get_value "${PARAM_CONTENT}" Qos`
ENCALGO=`get_value "${PARAM_CONTENT}" EncAlgo`
ENCKEY=`get_value "${PARAM_CONTENT}" EncKey`
ASMSIDNAME=`get_value "${PARAM_CONTENT}" ASMInstanceName`
ORA_DB_USER=`get_value "${PARAM_CONTENT}" OracleInstallUser`
ORA_GRID_USER=`get_value "${PARAM_CONTENT}" GridInstallUser`
IPPORTINFO=`get_value "${PARAM_CONTENT}" IpPortInfo`
NODENUMBER=`get_value "${PARAM_CONTENT}" NodeNumber`
ORACLE_BASE=`get_value "${PARAM_CONTENT}" AccessOracleBase`
ORACLE_HOME=`get_value "${PARAM_CONTENT}" AccessOracleHome`

#********************************test param vailed********************************
test "$DBNAME" = "ERROR_PARAM_INVALID"                           && exit_with_error "DBNAME"
test "$DBUUID" = "ERROR_PARAM_INVALID"                           && exit_with_error "DBUUID"
test "$DBINSTANCE" = "ERROR_PARAM_INVALID"                       && exit_with_error "DBINSTANCE"
test "$DBUSER" = "ERROR_PARAM_INVALID"                           && exit_with_error "DBUSER"
test "$ASMUSER" = "ERROR_PARAM_INVALID"                          && exit_with_error "ASMUSER"
test "$CHANNELS" = "ERROR_PARAM_INVALID"                         && exit_with_error "CHANNELS"
test "$BACKUP_PATH_LIST" = "ERROR_PARAM_INVALID"                 && exit_with_error "BACKUP_PATH_LIST"
test "$ARCHIVE" = "ERROR_PARAM_INVALID"                          && exit_with_error "ARCHIVE"
test "$LEVEL" = "ERROR_PARAM_INVALID"                            && exit_with_error "LEVEL"
test "$QOS" = "ERROR_PARAM_INVALID"                              && exit_with_error "QOS"
test "$ENCALGO" = "ERROR_PARAM_INVALID"                          && exit_with_error "ENCALGO"
test "$ASMSIDNAME" = "ERROR_PARAM_INVALID"                       && exit_with_error "ASMSIDNAME"
test "$ORA_DB_USER" = "ERROR_PARAM_INVALID"                      && exit_with_error "OracleUser"
test "$NODENUMBER" = "ERROR_PARAM_INVALID"                       && exit_with_error "NODENUMBER"

BACKUP_PATH_LIST=`redirect_backup_path "${BACKUP_PATH_LIST}"`
MAIN_BACKUP_PATH=`echo "${BACKUP_PATH_LIST}" | $MYAWK -F ";" '{print $1}'`
ADDITIONAL="${MAIN_BACKUP_PATH}/additional"
BACKUP_TEMP="${MAIN_BACKUP_PATH}/tmp"
test -z "${BACKUP_PATH_LIST}"                                    && exit_with_error "data path"
test -z "${MAIN_BACKUP_PATH}"                                    && exit_with_error "main data path"

LOG_IS_BACKED_UP="${LOG_IS_VALID} and name like '${MAIN_BACKUP_PATH}/log/arch_%'"

if [ -z "${CHANNELS}" ] || [ "${CHANNELS}" -eq 0 ]; then 
    CHANNELS=4
    log_warn "Setting channels number to ${CHANNELS} by default"
fi

if [ -z "$QOS" ]; then
    QOS=0
fi

if [ "${CHANNELS}" -gt 254 ]; then
    log_error "Channels param is invalid "
    exit "${RETURN_INVALID}"
fi

IS_ENC_BK=0
if [ -n "${ENCALGO}" ] && [ -n "${ENCKEY}" ]; then
    IS_ENC_BK=1
    RMAN_ENC_SECTION="configure encryption for database on; configure encryption algorithm '${ENCALGO}'; set encryption on identified by \"${ENCKEY}\" only; set decryption identified by \"${ENCKEY}\";"
    log_info "Backup database will enc "
fi



#********************************check host enviroment begin********************************
#get oracle user info
get_oracle_user

#get oracle user shell type
get_oracle_user_shell_type

env_file_list=`get_user_env_file "${ORA_DB_USER}"`
if [ $? -ne 0 ] || [ -z "$env_file_list" ]; then
    log_error "Get user env file failed"
    exit "$RETURN_INVALID"
fi

EXPORT_ORACLE_ENV=`generate_export_cmd "$env_file_list" "oracle"`
if [ $? -ne 0 ] || [ -z "$EXPORT_ORACLE_ENV" ]; then
    log_error "Get user env cmd failed"
    exit "$RETURN_INVALID"
fi

# check oracle install
check_oracle_is_install

# check oracle install type
check_oracle_install_type

if [ "$DBISCLUSTER" -gt 0 ]; then
    # get grid user
    get_grid_user

    get_grid_user_shell_type
    get_grid_home_path
    
    env_file_list=`get_user_env_file "${ORA_GRID_USER}"`
    if [ $? -ne 0 ] || [ -z "$env_file_list" ]; then
        log_error "Get user env file failed"
        exit "$RETURN_INVALID"
    fi

    EXPORT_GRID_ENV=`generate_export_cmd "$env_file_list" "grid"`
    if [ $? -ne 0 ] || [ -z "$EXPORT_GRID_ENV" ]; then
        log_error "Get user env cmd failed"
        exit "$RETURN_INVALID"
    fi

    ASMSIDNAME=`ps -ef | grep asm_...._+ | grep -v grep | ${MYAWK} -F_ '{print $NF}' | uniq`
    if [ -z "$ASMSIDNAME" ]; then
        log_error "Have no asm instance"
        exit "${RETURN_INVALID}"
    fi
fi

#get oracle base path
get_oracle_base_path

#get oracle home path
get_oracle_home_path

#get oracle version
get_oracle_version

check_sqlplus_status

check_rman_status

check_mount_path "$MAIN_BACKUP_PATH"

DBINSTANCE=`get_real_instance_name "${DBINSTANCE}"`
test -z "${DBINSTANCE}"                                    && exit_with_error "DB real instance name"
log_info "Check cluster [DBISCLUSTER=${DBISCLUSTER}], DBINSTANCE=${DBINSTANCE}."
#********************************check host enviroment end********************************

log_info "SCRIPTPID=${SCRIPTPID};INNERPID=${PID};DBUUID=${DBUUID};DBINSTANCE=${DBINSTANCE};DBName=${DBNAME};\
DBUSER=${DBUSER};ASMInst=${ASMSIDNAME};ASMUSER=${ASMUSER};IN_ORACLE_HOME=${IN_ORACLE_HOME};\
BACKUP_PATH_LIST=${BACKUP_PATH_LIST};ARCHIVE=${ARCHIVE};LEVEL=${LEVEL};CHANNELS=${CHANNELS};QOS=${QOS};\
ENCALGO=${ENCALGO};IPPORTINFO=${IPPORTINFO};NODENUMBER=${NODENUMBER};ORACLE_BASE=${ORACLE_BASE};\
ORACLE_HOME=${ORACLE_HOME}."

#********************************prepare for backup begin********************************
log_info "Create directory"
create_dir "$BACKUP_PATH_LIST"
create_dir "$BACKUP_TEMP"
create_dir "$ARCHIVE"
create_dir "$ADDITIONAL"
create_dir "$ADDITIONAL"/dbs
create_dir "$MAIN_BACKUP_PATH"/log

chown -R root "$ADDITIONAL"
chmod 700 "$ADDITIONAL"

log_info "check directory privilege"
check_dir_rwx "${ORA_DB_USER}" "${BACKUP_PATH_LIST}"            || exit_with_error "check data path"
check_dir_rwx "${ORA_DB_USER}" "${BACKUP_TEMP}"                 || exit_with_error "check backup tmp path"

if [ -n "${ARCHIVE}" ] ; then
    check_dir_rwx "${ORA_DB_USER}" "${ARCHIVE}"                 || exit_with_error "check log path"
fi

base_info=`get_database_base_info "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}"`
if [ $? -ne 0 ] || [ -z "$base_info" ]; then
    log_error "Get database base info failed"
    exit $?
fi
info_num=`echo "${base_info}" | $MYAWK '{print NF}'`
log_mode=`echo "${base_info}" | $MYAWK '{print $1}'`
db_id=`echo "${base_info}" | $MYAWK '{print $2}'`
uniq_dbname=`echo "${base_info}" | $MYAWK '{print $3}'`
if [ "$info_num" -gt 7 ]; then
    open_mode=`echo "${base_info}" | $MYAWK '{print $4$5$6$7}'`
    incarnation_number=`echo "${base_info}" | $MYAWK '{print $8}'`
    resetlogs_id=`echo "${base_info}" | $MYAWK '{print $9}'`
elif [ "$info_num" -eq 7 ]; then
    open_mode=`echo "${base_info}" | $MYAWK '{print $4$5}'`
    incarnation_number=`echo "${base_info}" | $MYAWK '{print $6}'`
    resetlogs_id=`echo "${base_info}" | $MYAWK '{print $7}'`
else
    open_mode=`echo "${base_info}" | $MYAWK '{print $4}'`
    incarnation_number=`echo "${base_info}" | $MYAWK '{print $5}'`
    resetlogs_id=`echo "${base_info}" | $MYAWK '{print $6}'`
fi

if [ "${log_mode}" != "ARCHIVELOG" ]; then
    log_error "Archive Mode=No Archive Mode, check archive mode failed."
    exit "${ERROR_ORACLE_NOARCHIVE_MODE}"
fi

log_info "Write backup metadata info"
echo "${db_id};${uniq_dbname};${DBINSTANCE};${ASMUSER};${ASMSIDNAME};\
${DBISCLUSTER};${ORA_PREVERSION_EXTEND};${incarnation_number};${resetlogs_id};${ORA_VERSION}" > "$ADDITIONAL"/dbinfo

echo "ORACLE_BASE=${IN_ORACLE_BASE}" > "$ADDITIONAL"/env_file
echo "ORACLE_HOME=${IN_ORACLE_HOME}" >> "$ADDITIONAL"/env_file
#********************************prepare for backup end********************************


#********************************backup data file begin********************************

datafile_min_scn=`get_datafile_mini_scn "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}"`
ret_code=$?
if [ ${ret_code} -ne 0 ]; then
    log_error "Get datafile mini scn failed"
    exit ${ret_code}
fi
test -z "$datafile_min_scn" && exit_with_error "min data file scn"



dbf_info="${STMP_PATH}/get_datafile_info_rst_${PID}.sql"
get_datafile_info "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" "${dbf_info}"
ret_code=$?
if [ $ret_code -ne 0 ]; then
    log_error "Get database data file info failed."
    delete_file "${dbf_info}"
    exit ${ret_code}
fi

start_with_spfile_flag="true"
spfile_info=`get_dbfiles "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" 1`
if [ $? -ne 0 ] || [ -z "$spfile_info" ]; then
    log_error "Get spfile file info failed."
    start_with_spfile_flag="false"
fi
log_info "start_with_spfile_flag:${start_with_spfile_flag}"

create_pfile_from_spfile "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" "${start_with_spfile_flag}"
ret_code=$?
if [ $? -ne 0 ]; then
    delete_file "${dbf_info}"
    log_error "Create database pfile failed"
    exit ${ret_code}
fi
if [ "$LEVEL" -ne 0 ]; then
    cross_check_backup_dbf "${DBINSTANCE}" "${DBNAME}" "${DBUSER}" "${DBUSERPWD}"
fi
cross_check_archive_log "${DBINSTANCE}" "${DBNAME}" "${DBUSER}" "${DBUSERPWD}" "${datafile_min_scn}"

backup_database_sql="${STMP_PATH}/backup_database_sql_${PID}.sql"
backup_database_rst="${STMP_PATH}/backup_database_rst_${PID}.sql"
build_backup_database_sql "${backup_database_sql}" "${dbf_info}" "${datafile_min_scn}" "${open_mode}" "${start_with_spfile_flag}"
chown "${ORA_DB_USER}" "${backup_database_sql}"
chmod 700 "${backup_database_sql}"

START_BACKUP_TIME=`date "+%Y-%m-%d_%H:%M:%S"`
log_info "Start running RMAN to backup"
rman_exe_script "${DBUSER}" "${DBUSERPWD}" "${backup_database_sql}" "${backup_database_rst}" "${DBINSTANCE}" -1 1
ret_code=$?
if [ ${ret_code} -ne 0 ]; then
    log_error "Backup database-${DBINSTANCE} failed, error=${ret_code}, error is `cat "${backup_database_rst}"`"
    delete_file "${backup_database_sql}" "${backup_database_rst}" "${dbf_info}" "true"
    if [ "${ERROR_SCRIPT_EXEC_FAILED}" = "${ret_code}" ]; then
        exit "${ERROR_ORACLE_BACKUP_FAILED}"
    fi
    exit "${ret_code}"
fi
END_BACKUP_TIME=`date "+%Y-%m-%d_%H:%M:%S"`
log_info "Backup start time is ${START_BACKUP_TIME} end time is ${END_BACKUP_TIME}"
delete_file "${backup_database_sql}" "${backup_database_rst}" "true"
log_info "Backup database-${DBINSTANCE} succ."

backup_end_scn=`get_datafile_mini_scn "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}"`
ret_code=$?
if [ ${ret_code} -ne 0 ]; then
    log_error "Get datafile mini scn failed"
    exit ${ret_code}
fi
database_role=`get_db_role "${instance_name}" "${db_user}" "${db_password}"`
if [ "${database_role}" = "PRIMARY" ]; then
  node_list=`get_database_node_list "${instance_name}" "${db_user}" "${db_password}"`
else
  node_list=`get_database_node_list_standby "${instance_name}" "${db_user}" "${db_password}"`
fi
check_archive_log_lost='false'
last_log_scn_info=`get_min_of_last_log_scn_by_thread "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}"`
last_log_scn=`echo "${last_log_scn_info}" | ${MYAWK} '{print $1}'`
last_log_time=`echo "${last_log_scn_info}" | ${MYAWK} '{print $2}'`
last_log_timestamp=`add_unix_timestamp "${last_log_time}"`
last_log_timestamp=$(echo "${last_log_timestamp}" | tail -n 1)
echo "last_backup_scn;${last_log_scn}" > "${RESULT_FILE}"
echo "timeStamp;${last_log_timestamp}" >> "${RESULT_FILE}"
echo "resetlogs_id;${resetlogs_id}" >> "${RESULT_FILE}"
echo "check_archive_log_lost;${check_archive_log_lost}" >> "${RESULT_FILE}"
echo "$last_log_scn $last_log_time $last_log_timestamp" > "$ADDITIONAL"/scn_dbf_max
log_info "Databackuprst;${last_log_scn};${last_log_time};${last_log_timestamp};${resetlogs_id}"


#********************************backup data file end**************************************

#********************************after backup data file begin******************************
move_pfile_to_stmp
if [ $? -ne 0 ]; then
    log_error "Move pfile to stmp failed."
    exit "${RETURN_INVALID}"
fi
echo "pfile;tempfile_${PID}" >> "${RESULT_FILE}"
log_info "pfile;tempfile_${PID}" 

echo "BackupLevel;${LEVEL}" >> "${RESULT_FILE}"
log_info "BackupLevel; ${LEVEL}"

log_info "Recording database control files"
control_file_info=`get_dbfiles "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" 0`
if [ $? -ne 0 ] || [ -z "$control_file_info" ]; then
    log_error "Get control file info failed."
    exit "${RETURN_INVALID}"
fi
echo "${control_file_info}" > "$ADDITIONAL"/ctrlfiles

log_info "Recording database spfile"
if [ "${start_with_spfile_flag}" = "true" ]; then
    spfile_info=`get_dbfiles "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" 1`
    if [ $? -ne 0 ] || [ -z "$spfile_info" ]; then
        log_error "Get spfile file info failed."
        exit "${RETURN_INVALID}"
    fi
    echo "${spfile_info}" > "$ADDITIONAL"/spfile
fi
log_info "Recording database Data Guard configuration file"
dataguardconffiles_info=`get_dbfiles "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" 2`
if [ $? -ne 0 ]; then
    log_error "Get dataguard conf file info failed."
    exit "${RETURN_INVALID}"
fi
echo "${dataguardconffiles_info}" > "$ADDITIONAL"/dataguardconffiles

log_info "Recording database data files and tablespace"
delete_file "$ADDITIONAL/dbfiles"
while read line; do
    [ -z "$line" ] && continue
    echo "$line" | $MYAWK -v OFS=";" '{print $1,$2,$3,$4}' >> "$ADDITIONAL/dbfiles"
done < "${dbf_info}"
delete_file "${dbf_info}"

log_info "Recording database online log info"
tmp_rst="${STMP_PATH}/get_online_log_info_rst_${PID}.txt"
get_online_redo_log_info "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" "${tmp_rst}"
if [ $? -ne 0 ]; then
    log_error "Get database online log file info failed."
    delete_file "${tmp_rst}"
    exit "${RETURN_INVALID}"
fi
delete_file "$ADDITIONAL/logfiles"
while read line; do
    [ -z "$line" ] && continue
    echo "$line" | $MYAWK -v OFS=";" '{print $1,$2}' >> "$ADDITIONAL/logfiles"
done < "$tmp_rst"
delete_file "${tmp_rst}"

log_info "Copying some additional info"
generate_additional_info

if [ "$LEVEL" -eq 0 ] && [ ! -f "$ADDITIONAL/first_backup_success" ]; then
    touch "$ADDITIONAL/first_backup_success"
fi

get_dir_file_info "${MAIN_BACKUP_PATH}" "${ORA_DB_USER}"
echo "filelist;filelist${PID}" >> "${RESULT_FILE}"
log_info "filelist;filelist${PID}"

# 将日志记录置为无效，以免被其他备份任务使用
change_archive_log_unavailable "data"
#********************************after backup data file end******************************

#chmod 640 RESULT_FILE
if [ -f "${RESULT_FILE}" ]; then
    chmod 640 "${RESULT_FILE}"
fi

delete_file "${SCRIPTPID_FILE}"
log_info "Do backup success."